#ifndef __DECIDER__
#define __DECIDER__

#include <memory>
#include <string>
#include <vector>

#include "dependence/any_container.h"
#include "dependence/make_enum_with_str.h"
#include "frame_macro.h"

/**
 * 纯虚类 Decider
 * Decider是决策子模块的顶层基类，每层决策的具体决策器都通过一个纯虚类间接继承此类。
 */

namespace decider {

class Decider {
  public:
    MAKE_ENUM(_Status,
              Unknown,    // 未知，一般为暂未执行
              Error,      // 执行错误，系统应该报错或退出
              Processing, // 正在执行，执行未完成，不能退出
              Done        // 执行完成：TODO 上层决策器重置之前，本决策器无法再次进入
    );

    virtual std::string DeciderID() = 0;

  protected:
    std::vector<std::shared_ptr<Decider>> sub_deciders_       = {};
    std::shared_ptr<Decider>              cur_sub_decider_    = nullptr;
    bool                                  first_time_process_ = true;
    AnyContainer                          params_             = {};
    _Status                               status_             = {_Status::Unknown};

  public:
    /* constructing need */
    Decider() = default;

  public: /* get */
    auto SubDeciders() -> std::vector<std::shared_ptr<Decider>> { return sub_deciders_; }
    auto FirstTimeProcess() -> bool { return first_time_process_; }
    auto Params() -> AnyContainer& { return params_; }
    auto Status() -> _Status { return status_; }
    auto GetSubDecider(std::string id) -> std::shared_ptr<Decider> {
        for (const auto& sub : sub_deciders_)
            if (sub->DeciderID() == id) return sub;
        return nullptr;
    }

  public: /* set */
    template <class T_SubDecider>
    void AddSubDecider(std::shared_ptr<T_SubDecider> sub_decider) {
        sub_deciders_.emplace_back(std::dynamic_pointer_cast<Decider>(sub_decider));
    }
    void SetStatus(_Status status) { status_ = status; }

  public: /* core function virtual */
    /* 决策器初始化 */
    virtual void Init() = 0;
    /* 决策器执行 */
    virtual auto Ready() -> bool      = 0;
    virtual auto TryProcess() -> bool = 0;
    virtual auto Process() -> _Status = 0;

    /* 决策器变量重置 */
    virtual void Reset() { params_.Reset(); }

    /* 选择子决策器 */
    auto SelectSubDecider() -> std::shared_ptr<Decider> {
        std::cout << "D|" << DeciderID() << ": select sub decider" << std::endl;

        if (sub_deciders_.size() == 1 and sub_deciders_.at(0)->DeciderID() == "DefaultDecider") return nullptr;

        auto admittances = std::vector<std::shared_ptr<Decider>>{};
        for (const auto& sub_decider : sub_deciders_) {
            auto enter_step = uint{0};
            std::cout << "DSub| " << sub_decider->DeciderID() << std::endl;
            if (sub_decider->Ready()) {
                ++enter_step;
                std::cout << " Ready";
            }
            if (sub_decider->TryProcess()) {
                ++enter_step;
                std::cout << " TrySuccess";
            }
            if (sub_decider->Status() != _Status::Error) {
                ++enter_step;
                std::cout << " StatusOK";
            }
            if (enter_step == 3) admittances.emplace_back(sub_decider);
        }
        if (admittances.size() == 0)
            return GetSubDecider("DefaultDecider");
        else if (admittances.size() == 1)
            return admittances.front();
        else {
            std::cout << "D|" << DeciderID() << ": More than one sub_deciders provided admittances: ";
            for (auto& ad : admittances) { std::cout << ad->DeciderID() << " "; }
            std::cout << std::endl;
            return GetSubDecider("DefaultDecider");
        }
    }

    /* 递归执行 */
    void ProcessOnce() {
        std::cout << "D|" << DeciderID() << ": Processing..." << std::endl;
        Process();
        first_time_process_ = false;
        if (Status() == _Status::Done or Status() == _Status::Error) {
            Reset();
            first_time_process_ = true;
            std::cout << "D|" << DeciderID()
                      << (Status() == _Status::Done ? ": [Done!]" //
                                                    : ": [Error!] check your code!")
                      << std::endl;
        }
        else if (Status() == _Status::Unknown or Status() == _Status::Processing) {
            auto sub_decider = SelectSubDecider();
            if (sub_decider == nullptr) std::cout << "D|" << DeciderID() << ": [Over!]" << std::endl;
            if (sub_decider != cur_sub_decider_ and cur_sub_decider_ != nullptr) cur_sub_decider_->Reset();
            cur_sub_decider_ = sub_decider;
            if (sub_decider != cur_sub_decider_ and cur_sub_decider_ != nullptr) cur_sub_decider_->Init();
            cur_sub_decider_->ProcessOnce();
        }
    }
};

} // namespace decider


#endif // __DECIDER__